#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "rngs.h"
#include <math.h>

#define VERBOSE 0

const char* getCardName(enum CARD card) {
	switch (card) {
		case curse: 				return "curse";
		case estate: 				return "estate";
		case duchy: 				return "duchy";
		case province: 			return "province";
		case copper: 			return "copper";
		case silver: 				return "silver";
		case gold: 				return "gold";
		case adventurer: 		return "adventurer";
		case council_room: 	return "council_room";
		case feast: 				return "feast";
		case gardens: 			return "gardens";
		case mine: 				return "mine";
		case remodel:  			return "remodel";
		case smithy: 			return "smithy";
		case village: 				return "village";
		case baron: 				return "baron";
		case great_hall: 		return "great_hall";
		case minion:				return "minion";
		case steward:  			return "steward";
		case tribute:				return "tribute";
		case ambassador:		return "ambassador";
		case cutpurse: 			return "cutpurse";
		case embargo: 			return "embargo";
		case outpost: 			return "outpost";
		case salvager: 			return "salvager";
		case sea_hag: 			return "sea_hag";
		case treasure_map: 	return "treasure_map";
	}
	return "";
}

void failureModePrint(struct gameState *state, char *failureMode, struct gameState *preState){
	if (VERBOSE == 1){
		int i;
		//Print out all the values of the gameState upon failure
		printf("This test failed due to %s!\n\n", failureMode);
		printf("The number of players was %d, and now is %d\n", preState->numPlayers, state->numPlayers);
		for(i = curse; i <= treasure_map; i++){
			printf("The supplyCount for %s card was %d, and now is %d\n", getCardName(i), preState->supplyCount[i], state->supplyCount[i]);
		}
		for(i = curse; i <= treasure_map; i++){
			printf("The embargo Tokens for %s card is %d\n", getCardName(i), state->embargoTokens[i]);
		}
		printf("The current turn was player %d\n", state->whoseTurn);
		for( i = 0; i < state->numPlayers; i++){
		printf("The current hand count for player %d was %d, and now is %d\n", i, preState->handCount[i], state->handCount[i]);
		printf("The current deck count for player %d was %d, and now is %d\n", i, preState->deckCount[i], state->deckCount[i]);
		printf("The current discard count for player %d was %d, and now is %d\n", i, preState->discardCount[i], state->discardCount[i]);
		}
	}
}

/*The smithy card effect is:
	Reveal cards from your deck until you reveal 2 Treasure cards. Put those Treasure cards in your hand and discard the other revealed cards.
*/
int main () {
	int i, n, choice1, choice2, choice3, handPos, successCount, badEffectCardReturn, badHandCount, badDiscardCount, currentPlayer, r, smithyHandCount, preSmithyHandCount, badSmithyHandCount, kingdomCardCount;
	int cardUnderTest = smithy;
	int *bonus = NULL;
	char *failureMode;
	int seed = 4;
	int numPlayer = 4;
	int k[10] = {smithy, council_room, feast, gardens, mine, remodel, smithy, village, baron, great_hall}; //quickly redone, but a staring point.
	struct gameState state;
	struct gameState preState;
	i = n = choice1 = choice2 = choice3 = handPos = successCount = badEffectCardReturn = badSmithyHandCount = badHandCount = badDiscardCount = currentPlayer = 0;
	//This is based on the sample code included in the dominion folder
	SelectStream(2);
	PutSeed((long)seed);
	for (n = 0; n < 1000000; n++) {
		//The random character filler for the game state would too often set up a segmentation fault that I could not isolate or remove, so I'm going to randomize each gameState value.  It lowers the amount of invalid space tested considerably.  However, now I won't have any seg faults which are truly no fun at all.
		memset(&state, 0, sizeof(struct gameState));
		memset(&preState, 0, sizeof(struct gameState));
		initializeGame(numPlayer, k, seed, &state); 
		initializeGame(numPlayer, k, seed, &preState); 
		//Begin gameState initialization
		preState.numPlayers = state.numPlayers = rand() % (MAX_PLAYERS - 1) + 2;
		for (i = curse; i < smithy; i++) {
			preState.supplyCount[i] = state.supplyCount[i] = rand() % 30; //30 is roughly the average of acceptable card levels for victory, and coins and curses.  This gives some invalid scenarios so it's a decent test.
		}
		kingdomCardCount = 0;
		//Roughly half of the kingdom cards are played on any given game, so if I used a 50% chance a kingdom card is in play and augment that chance to ensure the card under test is included and that there are not an invalid number for kingdom cards in play.
		preState.supplyCount[cardUnderTest] = state.supplyCount[cardUnderTest] = rand() % 12;
		kingdomCardCount++;
		for (i = smithy; i <= treasure_map; i++) {
			if(i == cardUnderTest) {
				//Skip setting supplyCount
			} else {
				if((10 - kingdomCardCount) > (treasure_map - i)) {
					//Then the remaining cards have to be in play to have 10 kingdom cards
					preState.supplyCount[i] = state.supplyCount[i] = rand() % 12;
					kingdomCardCount++;
				} else if (kingdomCardCount >= 10) {
					//We have the cards we need and have to set the rest to -1
					preState.supplyCount[i] = state.supplyCount[i] = -1;	//Then they are unused and set to -1
				}
				else {
					//There is a 50% chance that a card is added to the kingdom card piles
					if( rand() % 2 == 0) {
						preState.supplyCount[i] = state.supplyCount[i] = rand() % 12;
						kingdomCardCount++;
					} else {
						preState.supplyCount[i] = state.supplyCount[i] = -1;	//Then they are unused and set to -1
					}
				}
			}
		}
		
		//Set player decks and put the card under test in the hand of each player.
		for (i = 0; i < state.numPlayers; ++i) {
			preState.hand[i][0] = state.hand[i][0] = cardUnderTest;
			preState.deckCount[i] = state.deckCount[i] = rand() % MAX_DECK + 1;
			preState.discardCount[i] = state.discardCount[i] = rand() % MAX_DECK + 1;
			preState.handCount[i] = state.handCount[i] = rand() % MAX_HAND + 1;
		}  
		state.whoseTurn = rand() % state.numPlayers;
		
		//Now we have a state and we need to duplicate it to check for post conditions.
		//memcpy(&preState, &state, sizeof(struct gameState));
		//printf("kingdom card count %d\n\n", kingdomCardCount);
		//failureMode = "Test debug values";
		//failureModePrint(&state, failureMode);
		r = cardEffect(cardUnderTest, choice1, choice2, choice3, &state, handPos, bonus);
		currentPlayer = state.whoseTurn;
		//First make sure it returns correctly
		if(r != 0){
			badEffectCardReturn++;
			failureMode = "Bad Card Effect Return";
			failureModePrint(&state, failureMode, &preState);
		}
		//Then make sure the state changes occur as expected.  That includes checking that three additional cards are in the hand and the one additional card is in the discard pile.
		//Total hand should be plus 2
		if(state.handCount[currentPlayer] != (preState.handCount[currentPlayer] + 2)){
			badHandCount++;
			if (VERBOSE == 1){printf("The values of current hand count is %d, the value of the previous hand count is %d\n", state.handCount[currentPlayer], preState.handCount[currentPlayer]);}
			failureMode = "Bad Hand Count";
			failureModePrint(&state, failureMode, &preState);
		}
		//Smithy hand
		smithyHandCount = 0;
		preSmithyHandCount = 0;
		for(i = 0; i < state.handCount[currentPlayer]; i++) {
			if(state.hand[currentPlayer][i] == smithy) {
				smithyHandCount++;
			}
		}
		for(i = 0; i < preState.handCount[currentPlayer]; i++) {
			if(preState.hand[currentPlayer][i] == smithy) {
				preSmithyHandCount++;
			}
		}
		//One fewer smithy card in the hand then before.
		if(smithyHandCount != (preSmithyHandCount - 1)){
			badSmithyHandCount++;
			if (VERBOSE == 1){printf("The values of current smithy hand count is %d, the value of the previous smithy hand count is %d\n", smithyHandCount, preSmithyHandCount);}
			failureMode = "Bad Smithy Hand Count";
			failureModePrint(&state, failureMode, &preState);
		}
		//Success
		//successCount++;
	}
	printf("The smithy card test returned with:\n%d card effect errors\n%d smithy hand count errors\n%d hand count errors\n", badEffectCardReturn, badSmithyHandCount, badHandCount);
	return 0;
}